package config

import (
	"errors"
	"fmt"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"log"
	"os"
	"reflect"
)

func loadFromFile(path string) (map[any]any, error) {
	if path == "" {
		return nil, errors.New("config file path is empty")
	}

	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	props := make(map[any]any)
	yErr := yaml.Unmarshal(data, &props)
	if yErr != nil {
		return nil, yErr
	}

	return props, nil
}

func doLoad() {
	log.Println("ready to load config files >>>>")
	log.Println("now, try to load config.yaml ...")

	props, err := loadFromFile("config.yaml")
	if err != nil {
		log.Println("failed to load config.yaml ignore it.", err)
	}

	fill(prop, props)

	env := getEnv()
	if env == "prod" {
		return
	}

	envConfPath := fmt.Sprintf("config_%v.yaml", env)
	log.Printf("try to load %s ...\n", envConfPath)
	crrEnvConf, err := loadFromFile(envConfPath)
	if err != nil {
		log.Printf("failed to load %v , ignore it\n", envConfPath)
		return
	}

	fill(prop, crrEnvConf)

	log.Printf("\n -------- config --------\n %v \n-------------------------\n", prop)
}

func doFill(tar reflect.Value, src reflect.Value) {
	if tar.Kind() != reflect.Map && src.Kind() != reflect.Map {
		return
	}

	itr := src.MapRange()
	for itr.Next() {
		k := itr.Key()
		sv := itr.Value()

		tv := tar.MapIndex(k)
		if tv.Kind() != reflect.Map || sv.Kind() != reflect.Map {
			tar.SetMapIndex(k, sv)
			continue
		}

		doFill(tv, sv)
	}
}

func fill(target, source map[any]any) {
	doFill(reflect.ValueOf(target), reflect.ValueOf(source))
}

func getEnv() string {
	env := os.Getenv("env")
	if env == "" {
		env = "prod"
	}
	return env
}
